package algo3.algothief.modelo;

import org.w3c.dom.Document;
import org.w3c.dom.Element;


public class Tiempo {
	
	private Reloj reloj;
	
	private String diaLimite;
	private Integer horaLimite;
	
	private boolean seLlegoALaFechaYHoraLimite;
	
	private static int horasDeSuenio = 8;
	
//-------------------------------------------------------------------------------------	
	
	public Tiempo(String dia, int hora) {
		this.reloj = new Reloj(dia, hora);
		
		this.diaLimite = null;
		this.horaLimite = null;
		
		this.seLlegoALaFechaYHoraLimite = false;
	}

//-------------------------------------------------------------------------------------	

	public Element serializar(Document doc) {
		Element elementoTiempo = doc.createElement("Tiempo");
		
		Element elementoReloj = reloj.serializar(doc);
		
		Element elementoDiaLimite = doc.createElement("DiaLimite");
		Element elementoHoraLimite = doc.createElement("HoraLimite");
		Element elementoSeLlegoAlLimite = doc.createElement("SeLlegoAlLimite");
		elementoDiaLimite.setAttribute("dia", diaLimite);
		elementoHoraLimite.setAttribute("hora", horaLimite.toString());
		elementoSeLlegoAlLimite.setAttribute("condicion", Boolean.toString(seLlegoALaFechaYHoraLimite));
		
		elementoTiempo.appendChild(elementoReloj);
		elementoTiempo.appendChild(elementoDiaLimite);
		elementoTiempo.appendChild(elementoHoraLimite);
		elementoTiempo.appendChild(elementoSeLlegoAlLimite);
					
		return elementoTiempo;
	}
		
	public static Tiempo hidratar(Document doc) {
		Element elementoTiempo = (Element)doc.getElementsByTagName("Tiempo").item(0);
		
		Element elementoDiaLimite = (Element)elementoTiempo.getElementsByTagName("DiaLimite").item(0);
		String diaLimite = elementoDiaLimite.getAttribute("dia");
			
		Element elementoHoraLimite = (Element)elementoTiempo.getElementsByTagName("HoraLimite").item(0);
		String horaLimiteEnFormaDeString = elementoHoraLimite.getAttribute("hora");
		int horaLimite = Integer.parseInt(horaLimiteEnFormaDeString);
		
		Element elementoSeLlegoAlLimite = (Element)elementoTiempo.getElementsByTagName("SeLlegoAlLimite").item(0);
		String seLlegoAlLimiteEnFormaDeString = elementoSeLlegoAlLimite.getAttribute("condicion");
		boolean seLlegoAlLimite = Boolean.parseBoolean(seLlegoAlLimiteEnFormaDeString);
		
		Reloj relojNuevo = Reloj.hidratar(doc);
		Object[] fechaYHora = relojNuevo.verFechaYHora();
		String diaActual = (String)fechaYHora[0];
		Integer horaActual = (Integer)fechaYHora[1];
		
		Tiempo tiempoNuevo = new Tiempo(diaActual, horaActual);
		tiempoNuevo.definirDiaYHoraLimite(diaLimite, horaLimite);
		tiempoNuevo.definirSiSeLlegoALaHoraLimite(seLlegoAlLimite);
		
		return tiempoNuevo;
	}
	
//-------------------------------------------------------------------------------------
	
	private void definirSiSeLlegoALaHoraLimite(boolean seLlegoAlLimite) {
		this.seLlegoALaFechaYHoraLimite = seLlegoAlLimite;
	}
	
	
	
	private int buscarFecha(String dia) {
		String[] dias = reloj.verDiasDeLaSemana(); 
		
		int indiceDia = -1;
		
		for (int i = 0; ( (indiceDia == -1) && (i < 7) ); i++) 
			if (dias[i].matches(dia)) indiceDia = i;
		
		return indiceDia;
	}
	
	private boolean verSiSeLlegoALaHoraLimite() {
		Object[] fechaYHoraActuales = reloj.verFechaYHora();
		String diaActual = (String)fechaYHoraActuales[0];
		Integer horaActual = (Integer)fechaYHoraActuales[1];
		
		boolean llegoElDiaLimite = (diaActual.matches(diaLimite));
		boolean llegoLaHoraLimite = (horaActual.intValue() == horaLimite.intValue());
		
		if ((llegoElDiaLimite) && (llegoLaHoraLimite)) 
			this.seLlegoALaFechaYHoraLimite = true;
		
		return this.seLlegoALaFechaYHoraLimite;
	}
	
	
	private int diferenciaDeDias(String unDia, String otroDia) {
		int unaFecha = this.buscarFecha(unDia);
		int otraFecha = this.buscarFecha(otroDia);
		
		if (unaFecha > otraFecha) otraFecha += 7;
		
		int diferenciaDeDias = Math.abs(otraFecha - unaFecha);
		
		return diferenciaDeDias;
	}
	
	private int[] diferenciaDeDiasYHoras(int diferenciaDeDias, int unaHora, int otraHora) {
		if (unaHora > otraHora) {
			otraHora += 24;
			
			if (diferenciaDeDias == 0) diferenciaDeDias = 7;
			diferenciaDeDias--;
		}
		
		int diferenciaDeHoras = Math.abs(otraHora - unaHora);
		
		int[] diferenciaDeDiasYHoras = { diferenciaDeDias, diferenciaDeHoras };
		
		return diferenciaDeDiasYHoras;
	}
	
	
	private void seDurmioElPolicia() {
		for (int i = 0; i < horasDeSuenio; i++) {
			reloj.avanzarTiempo(0, 1);
			this.verSiSeLlegoALaHoraLimite();
		}
	}
	
//-------------------------------------------------------------------------------------	
	
	public Object[] verFechaYHora() {
		return reloj.verFechaYHora();
	}
	
	public Object[] verFechaYHoraLimites() {
		Object[] fechaYHoraLimites = { diaLimite, horaLimite };
		return fechaYHoraLimites;
	}
	
	
	public void avanzarTiempo(int horas) {
		for (int i = 0; i < horas; i++) {
			reloj.avanzarTiempo(0, 1);
			boolean esDeNoche = reloj.verSiEsDeNoche();
			
			if (esDeNoche) 
				this.seDurmioElPolicia();
			
			this.verSiSeLlegoALaHoraLimite();
		}
	}
	
	
	public void definirDiaYHoraLimite(String diaLimite, int horaLimite) {
		this.diaLimite = diaLimite;
		this.horaLimite = horaLimite;
	}
	
	public boolean llegoAlLimite() {
		return this.seLlegoALaFechaYHoraLimite;
	}
	
	
	public int[] verTiempoRestante() {
		Object fechaYHora[] = reloj.verFechaYHora();
		String diaActual = (String)fechaYHora[0];
		int horaActual = (Integer)fechaYHora[1];
		
		int diasRestantes = this.diferenciaDeDias(diaActual, diaLimite);
		int[] diasYHorasRestantes = this.diferenciaDeDiasYHoras(diasRestantes, horaActual, horaLimite);
		
		return diasYHorasRestantes;
	}
}
